module mirshare;

import std.algorithm, std.datetime;
import mirdefine, mirgame, mirsound, mirevent;

import AGui.AGui;
import scene.scene, scene.intro, scene.login, scene.selectserver, scene.selectplayer, scene.gameplay;

import share.edcode, share.utility, share.protocol;
import common.imagearray, common.imagehandler, common.sprite, common.clientsocket, common.pen;



import allegro5.allegro;
import allegro5.allegro_image;
import allegro5.allegro_font;

const FRAME_RATE = 60;
const SOCKET_MESSAGE_RATE = 100;

const TestMode = false;
const KoreanVersion = false;
const EnglishVersion = true;
const ChinaVersion = false;

//const BoUseFindHack = true;
const BoNeedPatch = true;

// 2003/04/01
const VERSION_YEAR = 2005; //2003;
const VERSION_MON = 5; //8;
const VERSION_DAY = 1; //5;

//const LocalLanguage: TImeMode = imOpen;
const SERVERADDR = "211.174.174.130"; //"194.153.73.54"; //"210.121.143.205";

const SCREENWIDTH = 800;
const SCREENHEIGHT = 600;
const MAXBAGITEMCL = 52;
const ENEMYCOLOR = 69;

const MAXFONT = 4;
// 2003/02/11 ±×·ì¿ø Ç¥½Ã
const MAXVIEWOBJECT = 20;

const string[MAXFONT] FontKorArr =
[
	"Batang",
	"Gulrym",
	"Gungseo",
	"Dodum"
];

const string[MAXFONT] FontEngArr =
[
	"Courier New",
	"Arial",
	"MS Sans Serif",
	"Microsoft Sans Serif"
];

const CurFont = 0;
const CurFontName = "Courier New";

//HIT
const HIT_INCLEVEL = 14;
const HIT_INCSPEED = 60;
const HIT_BASE = 1400;
const RUN_STRUCK_DELAY = 3 * 1000;

const GoldName = "Gold";

const ALLEGRO_COLOR AlTransparentBlack = { r: 0, g: 0, b: 0, a: 0 };
const ALLEGRO_COLOR AlBlack = { r: 0, g: 0, b: 0, a: 1 };
const ALLEGRO_COLOR AlWhite = { r: 1, g: 1, b: 1, a: 1 };
const ALLEGRO_COLOR AlGray = { r: 128/255, g: 128/255, b: 128/255, a: 1 };
const ALLEGRO_COLOR AlSilver = { r: 192/255, g: 192/255, b: 192/255, a: 1 };
const ALLEGRO_COLOR AlGold = { r: 1, g: 215/255, b: 0, a: 1 };
const ALLEGRO_COLOR AlRed = { r: 1, g: 0, b: 0, a: 1 };
const ALLEGRO_COLOR AlYellow = { r: 1, g: 1, b: 0, a: 1 };
const ALLEGRO_COLOR AlGreen = { r: 0, g: 1, b: 0, a: 1 };
const ALLEGRO_COLOR AlBlue = { r: 0, g: 0, b: 1, a: 1 };
const ALLEGRO_COLOR AlFuchsia = { r: 1, g: 0, b: 1, a: 1 };
const ALLEGRO_COLOR AlViolet = { r: 238/255, g: 130/255, b: 238/255, a: 1 };
const ALLEGRO_COLOR AlAqua = { r: 0, g: 1, b: 1, a: 1 };
const ALLEGRO_COLOR AlCornflowerBlue = { r: 100/255, g: 149/255, b: 237/255, a: 1 };



struct PacketMsg
{
    DefaultMessage  stDefMsg;
    char szEncodeData[1024];
}
alias PacketMsg* PPacketMsg;

struct KornetWorld
{
	string CPIPcode;
	string SVCcode;
	string LoginID;
	string CheckSum;
}

enum OneClickMode { None, KornetWorld };
enum TimerCommand { SoftClose, ReSelConnect, FastQueryChr, QueryItemPrice };
enum ChrAction { Walk, Run, Hit, Spell, Sitdown };
enum ConnectionStep { Login, SelChr, ReSelChr, Play };

public struct MovingItem
{
	int Index; //ItemArrÀÇ Index
	ClientItem Item;
}

// 2003/02/11 ViewObject...¹Ì´Ï¸Ê»ó¿¡ ±×·ì¿ø Ç¥½Ã
public struct MiniViewObject
{
	int Index;
	int X, Y;
	TickDuration LastTick;
}

public struct Chat
{
    public ALLEGRO_COLOR FontColor;
    public ALLEGRO_COLOR BackColor;
    public string Chat;
}


__gshared Game MyGame;
__gshared Pen MyPen;
__gshared ClientSocket MySocket;
__gshared SoundManager SoundMan;
__gshared GuiManager guiMan;
__gshared SceneManager SceneMan;
__gshared GameIntroScene IntroScene;
__gshared GameLoginScene LoginScene;
__gshared GameSelectServerScene SelectServerScene;
__gshared GameSelectPlayerScene SelectPlayerScene;
__gshared GamePlayScene PlayScene;
__gshared EventManager EventMan;
__gshared Sprite SpriteInfo;

__gshared bool g_bWantClosed;
__gshared int g_nCertifyCode;           // Global Certification Code
__gshared string g_szUserID;            // Global User ID
__gshared string g_szServerIP;          // Global Current Connection Server IP
__gshared ushort g_nServerPort;         // Global Current Connection Server Port
__gshared string g_szCharName;          // Global Charector Name
__gshared int g_nVersion;               // Global Client Program Version Number




uint random()
{
    auto r = std.random.rndGen.front();
    std.random.rndGen.popFront();
    return r;
}

uint random(int x)
{
    auto r = (std.random.rndGen.front() % x);
    std.random.rndGen.popFront();
    return r;
}

T randomRange(T)(T from, T to)   
{   
    alias gen = std.random.rndGen;  

    auto r = gen.front();
    gen.popFront();
    
    if ( r < 0 )   
        r = -r;   
    
    auto number = r % (to-from+1) + from;   
    
    return number; 
}

int iround(real x)
{
	return cast(int)std.math.lrint(x);
}

public void PomiTextOut(float x, float y, int color, in string str)
{
    const int red_offset = 1790;
    const int blue_offset = 1810;
    const int green_offset = 1830;

    int i, n, startoffset, offset;
    ALLEGRO_BITMAP* bmp;

    if (color == 0) startoffset = red_offset;
    else if (color == 1) startoffset = blue_offset;
    else if (color == 2) startoffset = green_offset;
    else startoffset = red_offset;

    for (i = 0; i < str.length; i++)
    {
        char digit = str[i];
        n = cast(int)(digit - '0');

        offset = -1;
        if (n >= 0 && n <= 9) // number
        {
            offset = startoffset + n;
        }
        else
        {
            if (str[i] == '-') offset = startoffset + 10;
            else if (str[i] == '+') offset = startoffset + 11;
        }

        if (offset >= 0)
        {
            // TODO:
            /*bmp = ImageMan[_IMAGE_INTER][offset];
            if (bmp !is null)
                al_draw_bitmap(bmp, x + i * 8, y, 0);*/
        }
    }
}

void SetBlendRenderState(ubyte bBlendFlag/*, D3DMATERIAL7 mtrlGetMtrl*/)
{
    //pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
    //pd3dDevice->SetRenderState(D3DRENDERSTATE_COLORKEYENABLE, TRUE);
    
    final switch ( bBlendFlag ) 
    {
        case _BLEND_NORMAL:
            /*if ( mtrlGetMtrl.diffuse.a < 1.0f || mtrlGetMtrl.emissive.a < 1.0f ) 
            {
                pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
                pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE);
                pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
                
                pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE);
                pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
            }
            else
            {
                pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
            }*/
            al_set_blender(ALLEGRO_BLEND_OPERATIONS.ALLEGRO_ADD, ALLEGRO_BLEND_MODE.ALLEGRO_ONE, ALLEGRO_BLEND_MODE.ALLEGRO_INVERSE_ALPHA);
            break;
        case _BLEND_LIGHT:
            al_set_blender(ALLEGRO_BLEND_OPERATIONS.ALLEGRO_ADD, ALLEGRO_BLEND_MODE.ALLEGRO_ONE, ALLEGRO_BLEND_MODE.ALLEGRO_ONE);
            //pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE);
            break;
        case _BLEND_LIGHTINV:
            al_set_blender(ALLEGRO_BLEND_OPERATIONS.ALLEGRO_ADD, ALLEGRO_BLEND_MODE.ALLEGRO_ONE, ALLEGRO_BLEND_MODE.ALLEGRO_INVERSE_SRC_COLOR);
            //pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCCOLOR);
            break;
        case _BLEND_INVNORMAL:
            /*if( mtrlGetMtrl.diffuse.a < 1.0f || mtrlGetMtrl.emissive.a < 1.0f )
            {
                pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE | D3DTA_COMPLEMENT);
                pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,   D3DTOP_MODULATE);
                pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
                pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
                pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE);
                pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
                
                pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE);
                pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
            } 
            else 
            {
                pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE | D3DTA_COMPLEMENT);
                pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,   D3DTOP_MODULATE);
                pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
                pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
                pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE);
                pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
                
                pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_INVSRCALPHA);
                pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO);
            }*/
            break;
        case _BLEND_INVLIGHT:
            /*pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE | D3DTA_COMPLEMENT);
            pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE|D3DTA_COMPLEMENT);
            pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1);
            pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVDESTCOLOR);*/
            break;
        case _BLEND_INVLIGHTINV:
            /*pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE|D3DTA_COMPLEMENT);
            pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1);
            pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE | D3DTA_COMPLEMENT);
            pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVDESTCOLOR);*/
            break;
    }
}

void ResetBlendenderState()
{
    //pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
    //pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,   D3DTOP_MODULATE);
    //pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
    //pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
    //pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1);
    //pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
    
    //pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
    //pd3dDevice->SetRenderState(D3DRENDERSTATE_COLORKEYENABLE, FALSE);
    //pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND , D3DBLEND_ONE);
    //pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO);
    al_set_blender(ALLEGRO_BLEND_OPERATIONS.ALLEGRO_ADD, ALLEGRO_BLEND_MODE.ALLEGRO_ONE, ALLEGRO_BLEND_MODE.ALLEGRO_ZERO);
}

public ALLEGRO_COLOR GetStateColor(int index)
{
    ALLEGRO_COLOR color = void;
    
    switch ( index )
    {
        case _STATE_RED:        color = AlRed; break;
        case _STATE_GREEN:      color = AlGreen; break;
        case _STATE_BLUE:       color = AlBlue; break;
        case _STATE_YELLOW:     color = AlYellow; break;
        case _STATE_FUCHSIA:    color = AlFuchsia; break;
        case _STATE_GRAY:       color = AlGray; break;
        default:                color = al_map_rgba(255, 255, 255, 255); break;
    }
    
    return color;
}

public ALLEGRO_COLOR GetChatColor(int index)
{
    ALLEGRO_COLOR color = void;
    
    switch ( index )
    {
        case _CHAT_COLOR1:      color = al_map_rgba(  0,   0,   0, 255); break;
        case _CHAT_COLOR2:      color = al_map_rgba( 10,  10,  10, 255); break;
        case _CHAT_COLOR3:      color = al_map_rgba(255, 255, 255, 255); break;
        case _CHAT_COLOR4:      color = al_map_rgba(255,   0,   0, 255); break;
        case _CHAT_COLOR5:      color = al_map_rgba(  0, 255,   0, 255); break;
        case _CHAT_COLOR6:      color = al_map_rgba(  0,   0, 255, 255); break;
        case _CHAT_COLOR7:      color = al_map_rgba(255, 255,   0, 255); break;
        case _CHAT_COLOR8:      color = al_map_rgba(255, 128,   0, 255); break;
        default:                color = al_map_rgba(255, 255, 255, 255); break;
    }
    
    return color;
}

public ALLEGRO_COLOR GetUserNameColor(int index)
{
    ALLEGRO_COLOR color = void;
    
    switch ( index )
    {
        case _USER_NAMECLR1:    color = al_map_rgba(255, 255, 255, 255); break;  // 255
        case _USER_NAMECLR2:    color = al_map_rgba(255, 255,   0, 255); break;  // 251
        case _USER_NAMECLR3:    color = al_map_rgba(255,   0,   0, 255); break;  // 249
        case _USER_NAMECLR4:    color = al_map_rgba(255,   0,   0, 255); break;  // 125
        case _USER_NAMECLR5:    color = al_map_rgba(165,  99,  57, 255); break;  // 47
        case _USER_NAMECLR6:    color = al_map_rgba(  0,   0, 255, 255); break;  // 180
        case _USER_NAMECLR7:    color = al_map_rgba(239, 107,   0, 255); break;  // 69
        case _USER_NAMECLR8:    color = al_map_rgba(  0, 148,   0, 255); break;  // 221
        case _USER_NAMECLR9:    color = al_map_rgba(  0, 255, 255, 255); break;  // 254
        case _USER_NAMECLR10:   color = al_map_rgba(140, 214, 239, 255); break;  // 147
        case _USER_NAMECLR11:   color = al_map_rgba( 57, 181, 239, 255); break;  // 154
        case _USER_NAMECLR12:   color = al_map_rgba(119, 136, 255, 255); break;  // 229
        case _USER_NAMECLR13:   color = al_map_rgba(  0, 123, 222, 255); break;  // 168
        case _USER_NAMECLR14:   color = al_map_rgba(  0,   0, 255, 255); break;  // 252
        default:                color = al_map_rgba(255, 255, 255, 255); break;  // 255
    }
    
    return color;
}